﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using ERTesting.Gui.ViewModel.Input;
using ERTesting.Model.Config;
using GalaSoft.MvvmLight;
using ERTesting.Gui.ViewModel.Config;
using ERTesting.Dao;
using GalaSoft.MvvmLight.Command;

namespace ERTesting.Gui.ViewModel
{
    /// <summary>
    /// This class contains properties that the main View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm/getstarted
    /// </para>
    /// </summary>
    public class MainViewModel : ViewModelBase
    {

        #region Private Members/Constants
        /// <summary>
        /// The <see cref="SelectedTestGroup" /> property's name.
        /// </summary>
        public const string SelectedTestGroupPropertyName = "SelectedTestGroup";

        private TestGroupViewModel _selectedTestGroup = null;
        private readonly ITestConfigService _testConfigService;


        /// <summary>
        /// The <see cref="CurrentView" /> property's name.
        /// </summary>
        public const string CurrentViewPropertyName = "CurrentView";

        private ViewModelBase _currentView = null;
        /// <summary>
        /// The <see cref="SelectedSheetConfig" /> property's name.
        /// </summary>
        public const string SelectSheetPropertyName = "SelectedSheetConfig";

        private SheetConfigViewModel _selectedSheetConfig = null;
        /// <summary>
        /// The <see cref="SheetConfigs" /> property's name.
        /// </summary>
        public const string SheetConfigsPropertyName = "SheetConfigs";

        private ObservableCollection<SheetConfigViewModel> _sheetConfigs = new ObservableCollection<SheetConfigViewModel>();

        #endregion Private Members/Constants


        #region Public Properties


        /// <summary>
        /// Gets the CurrentView property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public ViewModelBase CurrentView
        {
            get
            {
                return _currentView;
            }

            set
            {
                if (_currentView == value)
                {
                    return;
                }

                _currentView = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(CurrentViewPropertyName);
            }
        }

        /// <summary>
        /// Gets the SelectSheet property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public SheetConfigViewModel SelectedSheetConfig
        {
            get
            {
                return _selectedSheetConfig;
            }

            set
            {
                if (_selectedSheetConfig == value)
                {
                    return;
                }

                var oldValue = _selectedSheetConfig;
                _selectedSheetConfig = value;
                CurrentView = value;
                // Update bindings, no broadcast
                RaisePropertyChanged(SelectSheetPropertyName);

            }
        }

        /// <summary>
        /// The <see cref="OverlayViewModel" /> property's name.
        /// </summary>
        public const string OverlayViewModelPropertyName = "OverlayViewModel";

        private ViewModelBase _overlayViewModel = null;

        /// <summary>
        /// Gets the OverlayViewModel property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public ViewModelBase OverlayViewModel
        {
            get
            {
                return _overlayViewModel;
            }

            set
            {
                if (_overlayViewModel == value)
                {
                    return;
                }

                _overlayViewModel = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(OverlayViewModelPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="TestGroups" /> property's name.
        /// </summary>
        public const string TestGroupsPropertyName = "TestGroups";

        private ObservableCollection<TestGroupViewModel> _testGroups = new ObservableCollection<TestGroupViewModel>();

        /// <summary>
        /// Gets the TestGroups property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public ObservableCollection<TestGroupViewModel> TestGroups
        {
            get
            {
                return _testGroups;
            }

            set
            {
                if (_testGroups == value)
                {
                    return;
                }

                _testGroups = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(TestGroupsPropertyName);

            }
        }
        
        /// <summary>
        /// Gets the SheetConfigs property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public ObservableCollection<SheetConfigViewModel> SheetConfigs
        {
            get
            {
                return _sheetConfigs;
            }

            set
            {
                if (_sheetConfigs == value)
                {
                    return;
                }

                _sheetConfigs = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(SheetConfigsPropertyName);

            }
        }

        /// <summary>
        /// Gets the SelectedTestGroup property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public TestGroupViewModel SelectedTestGroup
        {
            get
            {
                return _selectedTestGroup;
            }

            set
            {
                if (_selectedTestGroup == value)
                {
                    return;
                }

                var oldValue = _selectedTestGroup;
                _selectedTestGroup = value;

                LoadTestGroupSheets(_selectedTestGroup);

                // Update bindings, no broadcast
                RaisePropertyChanged(SelectedTestGroupPropertyName);

            }
        }

        private void LoadTestGroupSheets(TestGroupViewModel selectedTestGroup)
        {
         _testConfigService.GetSheetsForGroup(selectedTestGroup.Group, (result, e) =>
                                                                     {
                                                                         if(result == null)
                                                                         {
                                                                             throw new ApplicationException("Unable to get sheets for test group.",e);
                                                                         }

                                                                         SheetConfigs = new ObservableCollection<SheetConfigViewModel>(from s in result select new SheetConfigViewModel(s, _testConfigService));
                                                                         SelectedSheetConfig = SheetConfigs.Count != 0 ? SheetConfigs[0]: null;
                                                                     });   
        }

        #endregion Public Properties

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel(ITestConfigService testConfigService)
        {
            if (IsInDesignMode)
            {
                // Code runs in Blend --> create design time data.
            }
            else
            {
                _testConfigService = testConfigService;
                LoadTestGroups();
            }
        }

        private void LoadTestGroups()
        {
            _testConfigService.GetTestGroups((groups, e) =>
                                                 {
                                                     if(groups == null)
                                                     {
                                                         throw new ApplicationException("Unable to load the set of testing groups.", e);
                                                     }

                                                     TestGroups = new ObservableCollection<TestGroupViewModel>(from g in groups select new TestGroupViewModel(g));
                                                     SelectedTestGroup = TestGroups.Count != 0 ? TestGroups[0] : null;
                                                 });
        }

        #region Commands

        private ICommand _addTestGroup;
        public ICommand AddTestGroup
        {
            get
            {
                if(_addTestGroup == null)
                {
                    _addTestGroup = new RelayCommand(()=>
                                                         {
                                                             NameInputViewModel nameInputViewModel = ViewModelLocator.Instance.GetViewModel<NameInputViewModel>("inputQuestion", "Please enter a name for the new test group:");
                                                             nameInputViewModel.GetInput((cancelled, value)=>
                                                                                             {
                                                                                                 if(!cancelled)
                                                                                                 {
                                                                                                     TestGroup testGroup = new TestGroup(value);
                                                                                                     _testConfigService.SaveTestGroup(testGroup);
                                                                                                     TestGroups.Add(ViewModelLocator.Instance.GetViewModel<TestGroupViewModel>("group", testGroup));
                                                                                                 }
                                                                                             });

                                                             
                                                         });

                }
                return _addTestGroup;
            }
        }


        private ICommand _addSheet;
        public ICommand AddSheet
        {
            get
            {
                if (_addSheet == null)
                {
                    _addSheet = new RelayCommand(() =>
                                                     {
                                                         SheetConfigViewModel sheetConfigViewModel = ViewModelLocator.Instance.GetViewModel<SheetConfigViewModel>(
                                                             "sheetConfig", new SheetConfig("Sheet name", SpreadsheetModeEnum.NewWorkbook));
                                                         OverlayViewModel = sheetConfigViewModel;
                                                     });

                }
                return _addSheet;
            }
        }

        private ICommand _removeSheet;
        public ICommand RemoveSheet
        {
            get
            {
                if (_removeSheet == null)
                {
                    _removeSheet = new RelayCommand<SheetConfigViewModel>((sheet) =>
                    {
                        if(sheet == null)
                        {
                            return;
                        }
                       if(MessageBox.Show("Are you sure you want to remove the sheet?","Are you sure?",MessageBoxButton.YesNo,MessageBoxImage.Question,MessageBoxResult.Yes) == MessageBoxResult.Yes)
                       {
                           _testConfigService.RemoveSheetConfig(sheet.Config);
                           SheetConfigs.Remove(sheet);
                       }


                    }, sheet => sheet != null);

                }
                return _removeSheet;
            }
        }

        #endregion Commands

        ////public override void Cleanup()
        ////{
        ////    // Clean up if needed

        ////    base.Cleanup();
        ////}
    }
}